$package("dowry.loader");

$import("dowry.loader.ClassLoader");
$import("dowry.test.Test");

$class("ClassLoaderTest").$extends("Test").$as(
{
    setup : function()
    {
        this.loader = new dowry.loader.ClassLoader();
    },

    testDefineClass : function()
    {
        this.loader.defineClass(null,
                                null,
                                "Foo",
                                null,
                                null,
                                {});

        this.assertNotNull(Foo);
        Foo = null;

        this.loader.defineClass("org.example",
                                null,
                                "Foo",
                                null,
                                null,
                                {});

        this.assertNotNull(org.example.Foo);
        org = null;

        this.loader.defineClass(null,
                                null,
                                "org.example.Foo",
                                null,
                                null,
                                {});

        this.assertNotNull(org.example.Foo);
        org = null;

        try
        {
            this.loader.defineClass("org.example",
                                    null,
                                    "Foo",
                                    "Dummy",
                                    null,
                                    {});

            this.assert(false);
        }
        catch(e)
        {
            this.assertNotNull(e);
        }
        org = null;
    },

    testDefineMixin : function()
    {
        this.loader.defineMixin(null,
                                null,
                                "Foo",
                                null,
                                {});

        this.assertNotNull(Foo);
        Foo = null;

        this.loader.defineMixin("org.example",
                                null,
                                "Foo",
                                null,
                                {});

        this.assertNotNull(org.example.Foo);
        org = null;

        this.loader.defineMixin(null,
                                null,
                                "org.example.Foo",
                                null,
                                {});

        this.assertNotNull(org.example.Foo);
        org = null;

        try
        {
            this.loader.defineMixin("org.example",
                                    null,
                                    "Foo",
                                    "Dummy",
                                    {});

            this.assert(false);
        }
        catch(e)
        {
            this.assertNotNull(e);
        }
        org = null;
    },

    testLoadClass : function()
    {
        this.assertNotNull(this.loader.loadClass("dowry.test.Test"));
        this.assertNotNull(dowry.test.Test);

        this.assertNull(this.loader.loadClass("org.example.Foo"));
    },

    testCallbacks : function()
    {
        this.loader.defineClass(null,
                                null,
                                "org.example.Foo",
                                null,
                                null,
                                { echo : function(o) { return o; } });


        this.assertNotNull(org.example.Foo);
        var o = new org.example.Foo();
        this.assertNotNull(o);
        this.assertEqual(o.echo("hi"), "hi");
        var f = o.echo.callback("hi");
        this.assertEqual(f(), "hi");
        f = o.echo.callback($VALUE);
        this.assertEqual(f("hi"), "hi");
        org = null;
    },

    testGlobals : function()
    {
        this.assertNotNull($classLoader);
        this.assertNotNull($VALUE);
        this.assertNotNull($package);
        this.assertNotNull($import);

        this.assertNotNull($class);
        this.assertNotNull($class("Class").$as);
        this.assertNotNull($class("Class").$extends);
        this.assertNotNull($class("Class").$extends("Super").$as);
        this.assertNotNull($class("Class").$with);
        this.assertNotNull($class("Class").$with("Mixin").$as);
        this.assertNotNull($class("Class").$extends("Super").$with);
        this.assertNotNull($class("Class").$extends("Super").$with("Mixin").$as);

        this.assertNotNull($mixin);
        this.assertNotNull($mixin("Mixin").$as);
        this.assertNotNull($mixin("Mixin").$extends);
        this.assertNotNull($class("Mixin").$extends("Super").$as);

        $package("org.example");
        $class("Foo").$as(
        {
        });
        this.assertNotNull(org.example.Foo);
        org = null;
    },

    testSuper : function()
    {
        $package("org.example");
        $class("Foo").$as(
        {
            doSomething : function(num)
            {
                return num;
            }
        });

        $package("org.example");
        $class("Bar").$extends("Foo").$as(
        {
            doSomething : function(num)
            {
                return 1 + this.$super(arguments);
            }
        });

        $package("org.example");
        $class("Baz").$extends("Foo").$as(
        {
            doSomething : function(num)
            {
                return this.$super([5]);
            }
        });


        var foo = new org.example.Foo();
        var bar = new org.example.Bar();
        var baz = new org.example.Baz();

        this.assertNotNull(foo);
        this.assertNotNull(bar);
        this.assertNotNull(baz);
        this.assertEqual(foo.doSomething(2), 2);
        this.assertEqual(bar.doSomething(2), 3);
        this.assertEqual(baz.doSomething(2), 5);

        org = null;
    },

    testStackTrace : function()
    {
        var c = $classLoader.loadClass("org.example.Bugged");
        this.assertNotNull(c);

        var o = new c();
        this.assertNotNull(o);

        try
        {
            o.buggy();
            this.assert(false);
        }
        catch(e)
        {
            this.assertEqual(e.className, "org.example.Bugged");
            this.assertEqual(e.methodName, "buggy");

            if (e.stack)
            {
                this.assertEqual(e.lineNumber, 7);
            }
        }

        c = $classLoader.loadClass("org.example.Bugged2");
        this.assertNotNull(c);

        o = new c();
        this.assertNotNull(o);

        try
        {
            o.buggy2();
            this.assert(false);
        }
        catch(e)
        {
            this.assertEqual(e.className, "org.example.Bugged2");
            this.assertEqual(e.methodName, "buggy2");

            if (e.stack)
            {
                this.assertEqual(e.lineNumber, 7);
            }
        }
    },

    teardown : function()
    {
        this.loader = null;
    }
});